package top.archiesean.sqlSession.impl;

import top.archiesean.pojo.Configuration;
import top.archiesean.pojo.MappedStatement;
import top.archiesean.sqlSession.SqlSession;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Proxy;
import java.lang.reflect.Type;
import java.util.List;

/**
 * @author ArchieSean
 * @create 2023/7/11
 */
public class DefaultSqlSession implements SqlSession {

    private Configuration configuration;

    public DefaultSqlSession(Configuration configuration) {
        this.configuration = configuration;
    }

    /**
     * 用于生成动态代理类
     *
     * @param mapperClass 需要代理的类
     * @param <T>         泛型
     * @return 返回代理类对象
     */
    @Override
    public <T> T getMapper(Class<?> mapperClass) {
        //基于jdk动态代理实现代理对象的创建
        Object newProxyInstance = Proxy.newProxyInstance(DefaultSqlSession.class.getClassLoader(),
                new Class[]{mapperClass},
                //代理对象每次调用方法，该方法都会执行
                (proxy, method, args) -> {
                    //准备参数： 1. statementId: sql语句的唯一标识：namespace.id
                    //方法名
                    String methodName = method.getName();
                    //获取该方法对应的字节码对象
                    String clazzName = method.getDeclaringClass().getName();
                    //statementId
                    String statementId = clazzName + "." + methodName;
                    //准备参数2： 方法入参：args
                    //获取方法返回值对象
                    Type returnType = method.getGenericReturnType();
                    //判断是否进行了泛型类型参数化
                    if (returnType instanceof ParameterizedType) {
                        return selectList(statementId, args);
                    }
                    return selectOne(statementId, args);
                });
        return (T) newProxyInstance;
    }

    @Override
    public <E> List<E> selectList(String statementId, Object... params) {
        //去完成对simpleExecutor里的query方法的调用
        SimpleExecutor executor = new SimpleExecutor();
        MappedStatement mappedStatement = configuration.getMappedStatementMap().get(statementId);
        List<Object> list = executor.query(configuration, mappedStatement, params);
        return (List<E>) list;
    }

    @Override
    public <T> T selectOne(String statementId, Object... params) {
        List<Object> list = selectList(statementId, params);
        if (list.size() == 1) {
            return (T) list.get(0);
        } else {
            throw new RuntimeException("查询结果为空或返回结果过多");
        }
    }
}
